﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Collections.Generic;
using SimpleJSON;
using Google.ProtocolBuffers;
using System.Threading;


namespace MyLib
{
	/// <summary>
    /// 处理网络连接
	/// Gate--->Forward OpenAgent To Somebody 
	/// 单线程程序
	/// </summary>
	public class Agent
	{
		private static uint maxId = 0;
		public uint id;

		//Socket mSocket;
		//ServerMsgReader msgReader;
		private bool _isClose = false;

		public bool isClose
		{
			get { return _isClose; }
			set { _isClose = value; }
		}

		public PlayerActor actor;
		public WatchDog watchDog;

		public SocketServer server;

		List<MsgBuffer> msgBuffer = new List<MsgBuffer>();
		public EndPoint ep;
		private byte[] mTemp = new byte[0x2000];

		private ulong mReceivePacketCount;
		private ulong mReceivePacketSizeCount;
		private ulong mSendPacketCount;
		private ulong mSendPacketSizeCount;

		public UDPAgent udpAgent;
		private KCPAgent kcpAgent;
        private TcpNetConnect tcpNetConnect;

		public void SetKCPAgent(KCPAgent kcp)
		{
			kcpAgent = kcp;
		}

		public void SetUDPAgent(UDPAgent ud)
		{
			udpAgent = ud;
		}
        /// <summary>
        /// 参考FPSServerMgr 收到新的链接
        /// </summary>
        /// <param name="socket"></param>
		public Agent(TcpNetConnect socket)
		{
            tcpNetConnect = socket;
            tcpNetConnect.tcpClient.Client.NoDelay = true;
			//socket.NoDelay = true;
			id = ++maxId;
			//mSocket = socket;
			//ep = mSocket.RemoteEndPoint;
            ep = tcpNetConnect.tcpClient.Client.RemoteEndPoint;

            tcpNetConnect.handler = handleMsg;
            tcpNetConnect.ClosedEvtHandler = Close;

			//msgReader = new ServerMsgReader();
			//msgReader.msgHandle = handleMsg;
			Debug.Log("AgentCreate " + id);
			var ip = ep as IPEndPoint;
			LogHelper.LogClientLogin(string.Format("ip={0}", ip.Address));
		}
       

		public void handleMsg(KBEngine.Packet packet)
		{
            LogHelper.Log2("Agent:ReceivePacket:"+packet.protoBody);
			if (actor != null)
			{
				actor.NetMsg(new ActorMsg() { packet = packet });
			}
			var size = 2 + packet.msglen;
			mReceivePacketCount += 1;
			mReceivePacketSizeCount += (ulong)size;
		}


		private int closeReq = 0;
		public void Close()
		{
			if (Interlocked.Increment(ref closeReq) != 1)
			{
				return;
			}

			if (isClose)
			{
				return;
			}
			isClose = true;

			LogHelper.Log("Agent", "CloseAgent");
            /*
			if (mSocket != null && mSocket.Connected)
			{
				Debug.LogError("CloseSocket");
				try
				{
					mSocket.Shutdown(SocketShutdown.Both);
					mSocket.Close();
				}
				catch (Exception exception)
				{
					Debug.LogError(Util.FlattenException(exception));
					//Util.PrintStackTrace();
				}
			}
			mSocket = null;
            */

			if (actor != null)
			{
                //actor.SendMsg(string.Format("close"));
                actor.NetMsg(new ActorMsg() {msg = "close"});
			}
			watchDog.Close(id);
            /*
			if (mSocket != null)
			{
				var ip = mSocket.RemoteEndPoint as IPEndPoint;
			}
            */
            LogHelper.LogClientLogout(string.Format("ip={0}", ep));
			if (server != null)
			{
				server.RemoveAgent(this);
			}
			if (udpAgent != null)
			{
				udpAgent.Close();
			}
			if (kcpAgent != null)
			{
				kcpAgent.Close();
			}
		}

    
		public bool useUDP = false;
		public void UseUDP()
		{
			if (!lostYet)
			{
				useUDP = true;
			}
		}

		public bool useKCP = false;
		public void UseKCP()
		{
			useKCP = true;
		}

		/// <summary>
		/// KCP连接一旦断开 需要重发一些数据给客户端
		/// 通过TCP发送数据 reInit 协议重新初始化
		/// 跟随初始化数据
		/// </summary>
		public void KCPLost()
		{
			useKCP = false;
		}

		private bool lostYet = false;
		public void UDPLost()
		{
			lostYet = true;
			useUDP = false;
		}


		/// <summary>
        /// 发送报文需要排队
        /// 
		/// 内部Actor将Agent要发送的消息推送给客户端 
		/// SendPacket 应该以SendBuff行驶发送
		/// 同一个Socket的Write Read只能加入一次 epoll 
		/// Read在初始化的时候加入
		/// Write在每次要写入的时候加入
		/// </summary>
		public void SendPacket(IBuilderLite retpb, byte ackId = 0, byte flowId = 0, byte errorCode = 0)
		{
			if (isClose)
			{
				return;
			}
            LogHelper.Log2("Agent:SendPacket:"+retpb.WeakBuild());
			mSendPacketCount += 1;
            tcpNetConnect.SendPacketAck(retpb, ackId, flowId);
		}
        public async Task SendWaitResponse(IBuilderLite cmd)
        {
            await tcpNetConnect.SendWaitResponse(cmd);
        }

		public JSONClass GetJsonStatus()
		{
			var sj = new SimpleJSON.JSONClass();

			var jsonObj = new JSONClass();
			jsonObj.Add("id", new JSONData(id));
			sj.Add("Agent", jsonObj);
			return sj;
		}
	}

}
